home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / human interface toolbox / modal textedit / main.c next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  12.1 KB  |  505 lines

  1. /*
  2.     File:        main.c
  3.  
  4.     Contains:    This snippet shows the steps necessary to implement a scrolling, editable text field
  5.                 in a dialog.  You may want to do this if you will be requiring the user to enter more than
  6.                 255 characters (the limit for editText items), if you want a different font for several
  7.                 different editText items, or it you want to add scrolling support to an editible text item.
  8.  
  9.     Written by: Steve Falkenburg    
  10.  
  11.     Copyright:    Copyright © 1984-1999 by Apple Computer, Inc., All Rights Reserved.
  12.  
  13.                 You may incorporate this Apple sample source code into your program(s) without
  14.                 restriction. This Apple sample source code has been provided "AS IS" and the
  15.                 responsibility for its operation is yours. You are not permitted to redistribute
  16.                 this Apple sample source code as "Apple sample source code" after having made
  17.                 changes. If you're going to re-distribute the source, we require that you make
  18.                 it clear in the source that the code was descended from Apple sample source
  19.                 code, but that you've made changes.
  20.  
  21.     Change History (most recent first):
  22.                 8/9/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  23.                 
  24.  
  25. */
  26. #include <Dialogs.h>
  27. #include <Fonts.h>
  28. #include <Windows.h>
  29. #include <TextEdit.h>
  30.  
  31. // constants
  32.  
  33. #define    kMyDialog        128
  34. #define    kInFront        (WindowPtr)-1L
  35. #define    kEditTextItem    2
  36. #define    kScrollerItem    3
  37. #define    kMargin            4
  38. #define    kPageLines        16
  39. #define    kScrollToTop    0
  40. #define    kScrollToBottom    1
  41. #define    kMaxLines        128
  42. #define    kCheckOneItem    5
  43. #define    kCheckTwoItem    6
  44.  
  45. // prototypes
  46.  
  47. void main(void);
  48. void InitStuff(void);
  49. void DoDialog(void);
  50. void SetupDialog(DialogPtr theDialog);
  51. void PrepareFreeDialog(DialogPtr theDialog);
  52.  
  53. pascal void EditTextDrawProc(DialogPtr theDialog,short theItem);
  54. pascal Boolean MyDialogFilter(DialogPtr theDialog,EventRecord *ev,short *itemHit);
  55. void HandleKeyPress(DialogPtr theDialog,char theChar);
  56. void HandleIdle(DialogPtr theDialog);
  57. void HandleActivate(DialogPtr theDialog);
  58. Boolean HandleMouse(DialogPtr theDialog,Point pt,short modifiers);
  59.  
  60. void HandleScroller(DialogPtr theDialog,Point pt);
  61. pascal void ScrollBarAction(ControlHandle theControl,short part);
  62. void ScrollText(DialogPtr theDialog,short lines);
  63. void ReAlignTextToScrollbar(DialogPtr theDialog);
  64. void ReAlignScrollbarToText(DialogPtr theDialog);
  65.  
  66. pascal Boolean MyTEClickProc(void);
  67.  
  68. ControlHandle GetScrollBar(DialogPtr theDialog);
  69. TEHandle GetTEHandle(DialogPtr theDialog);
  70.  
  71.  
  72. /* main entry point */
  73.  
  74. void main(void)
  75. {
  76.     InitStuff();
  77.     DoDialog();
  78.     ExitToShell();
  79. }
  80.  
  81.  
  82. /* initialize the Mac managers */
  83.  
  84. void InitStuff(void)
  85. {
  86.     InitGraf(&qd.thePort);
  87.     InitFonts();
  88.     InitWindows();
  89.     InitMenus();
  90.     TEInit();
  91.     InitDialogs(nil);
  92.     InitCursor();
  93.     FlushEvents(everyEvent,0);
  94. }
  95.  
  96.  
  97. /*    display dialog, and handle pretty standard ModalDialog loop.  The modal dialog loop doesn't
  98.     handle item hits to the scroll bar or text items.  These are handled through the filter
  99.     procedure
  100. */
  101.  
  102. void DoDialog(void)
  103. {
  104.     DialogPtr theDialog;
  105.     short item;
  106.     ControlHandle checkBoxControl;
  107.     short iType;
  108.     Rect iRect;
  109.     
  110.     theDialog = GetNewDialog(kMyDialog,nil,kInFront);
  111.     SetupDialog(theDialog);
  112.         
  113.     do {
  114.         ModalDialog(NewModalFilterProc(MyDialogFilter),&item);
  115.         switch (item) {
  116.             case kCheckOneItem:    // check boxes
  117.             case kCheckTwoItem:
  118.                 GetDialogItem(theDialog,item,&iType,&(Handle)checkBoxControl,&iRect);
  119.                 SetControlValue(checkBoxControl,!GetControlValue(checkBoxControl));
  120.                 break;
  121.         }    
  122.     } while (item!=ok);
  123.     
  124.     PrepareFreeDialog(theDialog);
  125.     DisposeDialog(theDialog);
  126. }
  127.  
  128.  
  129. /*    Creates the necessary data structures necessary to use the textedit item in our dialog.  A
  130.     handle to the TextEdit record is stored in the Dialog's window refCon field.
  131. */
  132.  
  133. void SetupDialog(DialogPtr theDialog)
  134. {
  135.     short iType;
  136.     Handle iHndl;
  137.     Rect iRect;
  138.     ControlHandle theControl;
  139.     short fontNum;
  140.     TEHandle theTE;
  141.     
  142.     SetPort(theDialog);
  143.     
  144.     GetDialogItem(theDialog,kScrollerItem,&iType,&(Handle)theControl,&iRect);    // set up the scroll bar
  145.     SetControlMinimum(theControl,0);                                        // (it's stored in a CNTL)
  146.     SetControlMaximum(theControl,kMaxLines);
  147.  
  148.     GetDialogItem(theDialog,kEditTextItem,&iType,&iHndl,&iRect);
  149.     SetDialogItem(theDialog,kEditTextItem,iType,(Handle)NewControlUserPaneDrawProc(EditTextDrawProc),&iRect);
  150.     
  151.     InsetRect(&iRect,kMargin,kMargin);
  152.     
  153.     GetFNum("\pgeneva",&fontNum);
  154.     TextFont(fontNum);
  155.     theTE = TENew(&iRect,&iRect);            // create our textedit item
  156.     GetFNum("\pchicago",&fontNum);
  157.     TextFont(fontNum);
  158.  
  159.     TESetClickLoop(NewTEClickLoopProc(MyTEClickProc),theTE);        // callback for drag-scrolling
  160.     TEAutoView(true,theTE);                    // turn auto-scroll on for text entry
  161.     
  162.     SetWRefCon(theDialog,(long)theTE);
  163. }
  164.  
  165.  
  166.  
  167. /*    free the memory taken by the textedit record before closing the dialog
  168. */
  169.  
  170. void PrepareFreeDialog(DialogPtr theDialog)
  171. {
  172.     TEHandle theTE;
  173.     
  174.     theTE = GetTEHandle(theDialog);
  175.     TEDispose(theTE);
  176. }
  177.  
  178.  
  179. /*    dialog user item draw procedure for text box.  It just calls FrameRect
  180. */
  181.  
  182. pascal void EditTextDrawProc(DialogPtr theDialog,short theItem)
  183. {
  184.     short iType;
  185.     Handle iHndl;
  186.     Rect iRect;
  187.     GrafPtr savePort;
  188.     
  189.     GetPort(&savePort);
  190.     SetPort(theDialog);
  191.     
  192.     GetDialogItem(theDialog,theItem,&iType,&iHndl,&iRect);
  193.     FrameRect(&iRect);
  194.     
  195.     SetPort(savePort);
  196. }
  197.  
  198.  
  199. /*    this is the main dispatcher for events to be passed off to the scroll bar or textedit box.
  200.     looks sort of like a WaitNextEvent event handler.
  201. */
  202.  
  203. pascal Boolean MyDialogFilter(DialogPtr theDialog,EventRecord *ev,short *itemHit)
  204. {
  205.     #pragma unused(itemHit)
  206.     char theChar;
  207.     
  208.     switch (ev->what) {
  209.         case keyDown:
  210.         case autoKey:
  211.             theChar = (ev->message & charCodeMask);
  212.             HandleKeyPress(theDialog,theChar);
  213.             return true;
  214.         case nullEvent:
  215.             HandleIdle(theDialog);
  216.             return false;
  217.         case activateEvt:
  218.             HandleActivate(theDialog);
  219.             return false;
  220.         case mouseDown:
  221.             return HandleMouse(theDialog,ev->where,ev->modifiers);
  222.         default:
  223.             return false;
  224.     }
  225. }
  226.  
  227.  
  228. /*    dialog filter event handler for keypresses.  All keypresses are passed to the textedit box
  229. */
  230.  
  231. void HandleKeyPress(DialogPtr theDialog,char theChar)
  232. {
  233.     TEHandle theTE;
  234.  
  235.     theTE = GetTEHandle(theDialog);
  236.     TEKey(theChar,theTE);
  237.     ReAlignScrollbarToText(theDialog);
  238. }
  239.  
  240.  
  241. /*    handler for null events.  used in our case to blink the insertion point
  242. */
  243.  
  244. void HandleIdle(DialogPtr theDialog)
  245. {
  246.     TEHandle theTE;
  247.  
  248.     theTE = GetTEHandle(theDialog);
  249.     TEIdle(theTE);
  250. }
  251.  
  252.  
  253. /*    activate event handler.  we take this opportunity to call TEActivate to activate the textedit
  254.     box
  255. */
  256.  
  257. void HandleActivate(DialogPtr theDialog)
  258. {
  259.     TEHandle theTE;
  260.  
  261.     theTE = GetTEHandle(theDialog);
  262.     TEActivate(theTE);
  263. }
  264.  
  265.  
  266. /*    mouse-down hander.  here, we see if the mousedown was in the scrollbar or in the textedit
  267.     record.  if in the textedit item, we call teclick.  If in the scrollbar, we call handlescroller
  268.     to do further processing
  269. */
  270.  
  271. Boolean HandleMouse(DialogPtr theDialog,Point pt,short modifiers)
  272. {
  273.     short iType;
  274.     Handle iHndl;
  275.     Rect textRect,scrollerRect;
  276.     TEHandle theTE;
  277.     GrafPtr savePort;
  278.     Boolean shiftDown,result;
  279.     
  280.     GetPort(&savePort);
  281.     SetPort(theDialog);
  282.     
  283.     shiftDown = modifiers & shiftKey;
  284.     GlobalToLocal(&pt);
  285.     
  286.     GetDialogItem(theDialog,kEditTextItem,&iType,&iHndl,&textRect);
  287.     GetDialogItem(theDialog,kScrollerItem,&iType,&iHndl,&scrollerRect);
  288.     
  289.     if (PtInRect(pt,&textRect)) {
  290.         theTE = GetTEHandle(theDialog);
  291.         TEClick(pt,shiftDown,theTE);
  292.         result = true;
  293.     }
  294.     else if (PtInRect(pt,&scrollerRect)) {
  295.         HandleScroller(theDialog,pt);
  296.         result = true;
  297.     }
  298.     else
  299.         result = false;
  300.         
  301.     SetPort(savePort);
  302.     
  303.     return result;
  304. }
  305.  
  306.  
  307. /*    here, we see which part of the scrollbar was clicked in by calling findcontrol.  trackcontrol
  308.     is then called with the appropriate action proc if in one of the buttons or page areas.  if
  309.     in the thumb, the text is simply re-aligned to the new scrollbar position
  310. */
  311.  
  312. void HandleScroller(DialogPtr theDialog,Point pt)
  313. {
  314.     short part;
  315.     ControlHandle theControl;
  316.     
  317.     part = FindControl(pt,theDialog,&theControl);
  318.     switch (part) {
  319.         case kControlUpButtonPart:
  320.         case kControlDownButtonPart:
  321.         case kControlPageUpPart:
  322.         case kControlPageDownPart:
  323.             TrackControl(theControl,pt,NewControlActionProc(ScrollBarAction));
  324.             break;
  325.         case kControlIndicatorPart:
  326.             TrackControl(theControl,pt,nil);
  327.             ReAlignTextToScrollbar(theDialog);
  328.             break;
  329.     }
  330. }
  331.  
  332.  
  333. /*    trackcontrol callback used to determine which direction to scroll the text, and by how much.
  334.     once this is known, the text is scrolled, and the scrollbar adjusted.
  335. */
  336.  
  337. pascal void ScrollBarAction(ControlHandle theControl,short part)
  338. {
  339.     DialogPtr theDialog;
  340.     short lines;
  341.     short ctlValue,ctlMax,ctlMin;
  342.     
  343.     ctlMax = GetControlMaximum(theControl);
  344.     ctlMin = GetControlMinimum(theControl);
  345.     ctlValue = GetControlValue(theControl);
  346.     
  347.     theDialog = (*theControl)->contrlOwner;
  348.     
  349.     switch (part) {
  350.         case kControlUpButtonPart:
  351.             lines = -1;
  352.             break;
  353.         case kControlDownButtonPart:
  354.             lines = 1;
  355.             break;
  356.         case kControlPageUpPart:
  357.             lines = -kPageLines;
  358.             break;
  359.         case kControlPageDownPart:
  360.             lines = kPageLines;
  361.             break;
  362.         default:
  363.             return;
  364.     }
  365.  
  366.     if ((ctlValue+lines)>ctlMax)
  367.         lines = ctlMax-ctlValue;
  368.     if ((ctlValue+lines)<ctlMin)
  369.         lines = ctlMin-ctlValue;
  370.         
  371.     if (lines!=0) {
  372.         ScrollText(theDialog,lines);
  373.         SetControlValue(theControl,ctlValue+lines);
  374.     }
  375. }
  376.  
  377.  
  378. /*    sets the text top line to be the same as the current scrollbar position.  this is called after
  379.     a thumb movement in the scrollbar.
  380. */
  381.  
  382. void ReAlignTextToScrollbar(DialogPtr theDialog)
  383. {
  384.     TEHandle theTE;
  385.     ControlHandle scrollBar;
  386.     short controlScrollPosition,textScrollPosition,scrollDelta,scrollPix;
  387.     
  388.     theTE = GetTEHandle(theDialog);
  389.     scrollBar = GetScrollBar(theDialog);
  390.     
  391.     controlScrollPosition = GetControlValue(scrollBar);
  392.     textScrollPosition = ((**theTE).viewRect.top - (**theTE).destRect.top) / (**theTE).lineHeight;
  393.     scrollDelta = textScrollPosition - controlScrollPosition;
  394.     scrollPix = scrollDelta * (*theTE)->lineHeight;
  395.     TEScroll(0,scrollPix,theTE);
  396. }
  397.  
  398.  
  399. /*    sets the scrollbar thumb to the current text position.  this is called after autoscrolling,
  400.     which may occur after a call to TEKey, or during a drag-scroll
  401. */
  402.  
  403. void ReAlignScrollbarToText(DialogPtr theDialog)
  404. {
  405.     TEHandle theTE;
  406.     ControlHandle scrollBar;
  407.     short textScrollPosition;
  408.         
  409.     theTE = GetTEHandle(theDialog);
  410.     scrollBar = GetScrollBar(theDialog);
  411.     
  412.     textScrollPosition = ((**theTE).viewRect.top - (**theTE).destRect.top) / (**theTE).lineHeight;
  413.     SetControlValue(scrollBar,textScrollPosition);
  414. }
  415.  
  416.  
  417. /*    scrolls the text by the delta passed in to the function.  called in response to clicking the
  418.     arrows or page areas of the scrollbar to move the text
  419. */
  420.  
  421. void ScrollText(DialogPtr theDialog,short lines)
  422. {
  423.     TEHandle theTE;
  424.     short scrollPix;
  425.     short textScrollPosition;
  426.     
  427.     theTE = GetTEHandle(theDialog);
  428.  
  429.     textScrollPosition = ((**theTE).viewRect.top - (**theTE).destRect.top) / (**theTE).lineHeight;
  430.     if ((textScrollPosition+lines)<0)
  431.         lines = -textScrollPosition;
  432.     if ((textScrollPosition+lines)>kMaxLines)
  433.         lines = kMaxLines-textScrollPosition;
  434.                 
  435.     scrollPix = lines * (*theTE)->lineHeight;
  436.     
  437.     TEScroll(0,-scrollPix,theTE);
  438. }
  439.  
  440.  
  441. /*    text drag callback procedure.  this routine handles drag scrolling by checking to see if we
  442.     are in the area where drag-scrolling is necessary, and calling scrolltext followed by a
  443.     scrollbar realignment
  444. */
  445.  
  446. pascal Boolean MyTEClickProc(void)
  447. {
  448.     Point pt;
  449.     DialogPtr theDialog;
  450.     TEHandle theTE;
  451.     Rect textRect;
  452.     short scrollLines;
  453.     GrafPtr savePort;
  454.     RgnHandle saveClip;
  455.         
  456.     GetMouse(&pt);
  457.     theDialog = (DialogPtr)FrontWindow();
  458.     theTE = GetTEHandle(theDialog);
  459.     
  460.     GetPort(&savePort);
  461.     SetPort(theDialog);
  462.  
  463.     saveClip = NewRgn();
  464.     GetClip(saveClip);
  465.     ClipRect(&theDialog->portRect);
  466.  
  467.     scrollLines = 0;
  468.     textRect = (**theTE).viewRect;
  469.     if (pt.v < textRect.top)
  470.         scrollLines = -1;
  471.     else if (pt.v > textRect.bottom)
  472.         scrollLines = 1;
  473.     
  474.     if (scrollLines) {
  475.         ScrollText(theDialog,scrollLines);
  476.         ReAlignScrollbarToText(theDialog);
  477.     }
  478.     
  479.     SetClip(saveClip);
  480.     DisposeHandle((Handle)saveClip);
  481.     SetPort(savePort);
  482.     return true;
  483. }
  484.  
  485.  
  486. /*    utility procedure to return a handle to the scrollbar control
  487. */
  488.  
  489. ControlHandle GetScrollBar(DialogPtr theDialog)
  490. {
  491.     ControlHandle theScroller;
  492.     short iType;
  493.     Rect iRect;
  494.     
  495.     GetDialogItem(theDialog,kScrollerItem,&iType,&(Handle)theScroller,&iRect);
  496.     return theScroller;
  497. }
  498.  
  499.  
  500. /*    utility procedure to return the textedit record for the given dialog */
  501.  
  502. TEHandle GetTEHandle(DialogPtr theDialog)
  503. {
  504.     return( (TEHandle)GetWRefCon((WindowPtr)theDialog) );
  505. }